package com.powergisol.gis.service.impl;

import com.powergisol.gis.dao.TabDataSettingMapper;
import com.powergisol.gis.dao.TabMarkerColorMapper;
import com.powergisol.gis.dao.TabTaskMapper;
import com.powergisol.gis.dao.TabYcMapper;
import com.powergisol.gis.entity.TabMarkerColor;
import com.powergisol.gis.entity.TabTask;
import com.powergisol.gis.entity.TabYc;
import com.powergisol.gis.exception.GlobalExceptionHandler;
import com.powergisol.gis.geom.GeoPoint;
import com.powergisol.gis.geom.GeoPolygon;
import com.powergisol.gis.geom.SpatialRelationship;
import com.powergisol.gis.service.TabYcService;
import com.powergisol.gis.util.FileUtil;
import com.powergisol.gis.util.Result;
import com.powergisol.gis.vo.*;
import org.apache.commons.lang.StringUtils;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.map.type.CollectionType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class TabYcServiceImpl implements TabYcService {

    @Autowired
    private TabYcMapper tabYcMapper;

    @Autowired
    private TabTaskMapper tabTaskMapper;

    @Resource
    private CacheManager cacheManager;

    @Value("${earth-url}")
    private String earthUrl;

    @Value("${yc-url}")
    private String ycUrl;

    @Autowired
    private TabDataSettingMapper settingMapper;

    @Autowired
    private TabMarkerColorMapper tabMarkerColorMapper;

    @Resource
    private RestTemplate restTemplate;
    @Value("${ZKLX}")
    private String ZKLX;


    @Override
    public TabYc saveTabYc(TabYc yc) {
        tabYcMapper.saveTabYc(yc);
        return yc;
    }

    @Override
    public Result upTabYc(String plane,String wall,String uuid) {
        Result result = new Result();
        TabYc yc = tabYcMapper.selectYcByUuid(uuid);
        if(null == yc){
           return  result.failure(500,"数据不存在");
        }
        yc.setPlane(plane);
        yc.setWall(wall);
        //修改状态
        yc.setState(1);
        tabYcMapper.upTabYc(yc);
        return result.success("修改成功");
    }

    @Override
    public void upTabYc(TabYc yc) {
        tabYcMapper.upTabYc(yc);
    }

    @Override
    public TabYc selectYcByUuid(String uuid) {
        return tabYcMapper.selectYcByUuid(uuid);
    }

    @Override
    public List<TabYc> getYcList(TabYc tabYc) {
        List<TabYc> list = tabYcMapper.getYcList(tabYc);
        if(0 == tabYc.getState()){
            //查询缓存
            Cache cache = cacheManager.getCache("cache-data");
            for (TabYc yc:list) {
                if(null != cache.get(yc.getUuid())){
                    Double ycProgres = cache.get(yc.getUuid(),Double.class);
                    yc.setYcProgress(ycProgres);
                }else{
                    yc.setYcProgress(0d);
                }
            }
        }
        return list;
    }

    @Override
    public List<TabYc> getYcListState(Integer state) {
        return tabYcMapper.getYcListState(state);
    }

    @Override
    public Result delYc(String uuid) {
        Result result = new Result();
        try{
            if(null == uuid || ("").equals(uuid)){
                return result.failure(415,"数据不能为空");
            }
            Map<String,Object> map = tabYcMapper.selectUserService(uuid);
            String serviceIds = map.get("serviceIds").toString();
            //删除岩层、服务、服务中间表、任务列表
            if(null != serviceIds && !("").equals(serviceIds)){
                tabYcMapper.delYcUserService(serviceIds);
            }
            tabTaskMapper.delTaskByUuid(uuid);
            tabYcMapper.delYc(uuid);
            tabYcMapper.delService(uuid);
//            tabYcMapper.delDataSetting(uuid);
            //根据serviceIds获取tab_yc的id
            String layerIds = tabYcMapper.selectLayerByServiceIds(serviceIds);
            //根据layerIds删除图层tab_layer和tab_tree
            if(StringUtils.isNotEmpty(layerIds)){
                tabYcMapper.delYcTree(layerIds);
                tabYcMapper.delLayerTree(layerIds);
            }
            //删除岩层颜色设置
            tabMarkerColorMapper.deleteMarker(uuid);

        }catch (Exception e){
            e.printStackTrace();
            return  result.failure(500,"系统异常请联系管理员");
        }
        return result;
    }

    @Override
    public Result generateYc(YcConditionVo vo, TabUserVo userVo) {
        Result result = new Result();
        List<String> zkData = vo.getZkData();

        Integer num = tabYcMapper.checkYcName(vo.getYcmc());
        if(num>0){
            return result.failure(415,"模型名称重复");
        }

        if(null == zkData || zkData.size() == 0){
            return result.failure(415,"数据为空");
        }
        List<TabMarkerColor> listColors = vo.getListColors();
        if(null == listColors || listColors.isEmpty()){
            return result.failure(415,"请指定岩层顺序");
        }
        //生成服务
        SimpleDateFormat sdf1=new SimpleDateFormat("yyyyMMddHHmmss");
        String serviceName = vo.getYcmc()+sdf1.format(new Date());
        TabServiceVo tabServiceVo = new TabServiceVo();
        tabServiceVo.setUserId(userVo.getId());
        tabServiceVo.setName(serviceName);
        tabServiceVo.setReleaseTime(new Date());
        tabServiceVo.setServiceType(12);
        tabServiceVo.setUuid(vo.getUuid());
        tabServiceVo.setState(1);
        tabServiceVo.setServiceUrl(earthUrl+serviceName);
        settingMapper.saveService(tabServiceVo);
        settingMapper.saveUserService(tabServiceVo.getUserId(),tabServiceVo.getId());

        //岩层存储及对应的颜色保存
        TabYc tabYc = new TabYc();
        tabYc.setYcTime(new Date());
        tabYc.setUuid(vo.getUuid());
        tabYc.setYcName(vo.getYcmc());
        // tabYc.setYcUser(p.getName());
        tabYc.setYcUser("admin");
        tabYc.setServiceId(tabServiceVo.getId());
        tabYc.setState(0);
        String userDir = System.getProperty("user.dir");
        String fileWallUrl = userDir+File.separator +"wall"+File.separator+vo.getUuid()+".json";
        String filePlaneUrl = userDir+File.separator +"plane"+File.separator+vo.getUuid()+".json";
        tabYc.setWall(fileWallUrl);
        tabYc.setPlane(filePlaneUrl);
        this.saveTabYc(tabYc);

        for (TabMarkerColor color:listColors) {
            color.setUuid(vo.getUuid());
            settingMapper.saveMarkerColor(color);
        }

        //生成任务
        TabTask tabTask = new TabTask();
        tabTask.setUserId(userVo.getId());
        tabTask.setUuid(vo.getUuid());
        tabTask.setTaskName(vo.getYcmc());
        tabTask.setTaskTime(new Date());
        tabTask.setTaskType(1);
        tabTask.setTaskState(0);
        tabTask.setProgress(0d);
        tabTask.setServiceName(serviceName);
        tabTask.setServiceType(12);
        tabTask.setServiceId(tabServiceVo.getId());
        tabTask.setServiceUrl(earthUrl+serviceName);
        tabTaskMapper.saveTabTask(tabTask);

        result.setData(tabYc);
        return result;
    }

    @Override
    @Async
    public Result generateYcNew(YcConditionVo vo) {
        Result r = new Result();
        List<String> zkData = vo.getZkData();
        //过滤点范围
        SpatialRelationship spatialRelationship = new SpatialRelationship();


        List<GeoPoint> pointList = new ArrayList<>();
        Map<String,Object> map = new HashMap<>();
        for (String str : zkData){
            String[] data = str.split(",");
            GeoPoint point = new GeoPoint(Double.valueOf(data[2]),Double.valueOf(data[3]));
            map.put("settingId",data[0]);
            map.put("ZKBH",data[1]);
            point.setProperties(map);
            pointList.add(point);
        }
        //根据经纬去重
        List<GeoPoint> pointListNew = pointList.stream().collect(Collectors.collectingAndThen(Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(o -> o.getX() + ";" + o.getY()))), ArrayList::new));
//       //根据编号和settingId去重
//        List<GeoPoint> pointListNew = pointListNew1.stream().collect(Collectors.collectingAndThen(Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(o -> o.getProperties().get("ZKBH") + ";" + o.getProperties().get("settingId")))), ArrayList::new));
        List<double[]> zkfw = vo.getZkfw();
        double[][] doubles = zkfw.toArray(new double[zkfw.size()][2]);
        GeoPolygon geoPolygon = new GeoPolygon(doubles);
        List<GeoPoint> intersects = spatialRelationship.intersects(pointListNew, geoPolygon);

        List<CreateYcBase> listYc = new ArrayList<>();
        StringBuffer buffer = new StringBuffer();
        TabTask tabTask = tabTaskMapper.getByUuid(vo.getUuid());
        //存放经纬度和
        double xTotal = 0d;
        double yTotal = 0d;
        StringBuffer bufferZKBH = new StringBuffer();
        //组装数据
        for (GeoPoint point:intersects) {
            CreateYcBase  ycBase = new CreateYcBase();
            String ZKBH = point.getProperties().getProperty("ZKBH");
            String settingId = point.getProperties().getProperty("settingId");
            ycBase.setId(settingId+point.getX()+"-"+ZKBH);

            xTotal = xTotal + point.getX();
            yTotal = yTotal + point.getY();

            if(!buffer.toString().contains(settingId)){
                buffer.append(settingId+",");
            }

            //钻孔对应的岩层
            List<CreateYcDataVo> datas = settingMapper.getYcData(ZKBH,settingId,point.getX(),point.getY());
//            //岩层去重
//            List<CreateYcDataVo> datas = dataYc.stream().collect(Collectors.collectingAndThen(Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(o -> o.getZKX() + ";" + o.getZKY()))), ArrayList::new));
//            System.out.println("钻孔对应岩层："+datas);
            List<Integer> zkfc = new ArrayList<>();
            List<BigDecimal> zkcdbg = new ArrayList<>();
            for (int i=0;i<datas.size(); i++) {
                CreateYcDataVo dataVo = datas.get(i);
                if(ZKLX.equals(dataVo.getZKLX())){
                    continue;
                }
                if(0 == i){
//                    ycBase.setX(dataVo.getZKOX());
//                    ycBase.setY(dataVo.getZKOY());
                    ycBase.setX(dataVo.getZKX());
                    ycBase.setY(dataVo.getZKY());
                    ycBase.setKgbg(dataVo.getZKBG());
                }

                //获取钻孔分层
                List<TabMarkerColor> listColors = vo.getListColors();
                for (TabMarkerColor color:listColors) {
                    boolean flag =color.getDrillMarker().equals(dataVo.getTCMC());
                    if(flag){
                        zkfc.add(color.getZkfc());
                        break;
                    }
                }
                zkcdbg.add(dataVo.getZkcdbg());
            }
            if(zkfc.size()>0){
                ycBase.setZkfc(zkfc);
                ycBase.setZkcdbg(zkcdbg);
                listYc.add(ycBase);
            }
        }
        TabYc tabYc = tabYcMapper.selectYcByUuid(vo.getUuid());
        tabYc.setSettingId(buffer.toString());
        try {
            ObjectMapper mapper = new ObjectMapper();
            System.out.println("调用生成岩层="+vo.getYcmc()+";="+new Date());
            String ycfw = vo.getYcfw();
            System.out.println("岩层范围="+ycfw);

            if(null == listYc || listYc.isEmpty() || listYc.size()<=3){
//                tabYc.setState(-1);
//                tabYcMapper.upTabYc(tabYc);
                tabYcMapper.delYc(vo.getUuid());

//                tabTask.setTaskState(2);
//                tabTask.setRemark("生成岩层失败:框选钻孔数量需4个及以上");
//                tabTask.setUpTime(new Date());
//                tabTask.setProgress(0d);
//                tabTaskMapper.upTabTask(tabTask);
                tabTaskMapper.delTask(vo.getUuid());
                return r.failure(-1,"框选钻孔数量需4个及以上");
            }
            String listYcData = mapper.writeValueAsString(listYc);
            System.out.println("岩层数据="+listYcData);
            //获取范围内钻孔经纬度平均值
            int num = intersects.size();
            double x = - xTotal/num;
            double y = - yTotal/num;
            DrillModel drillModel = new DrillModel();
            drillModel.setBoundary(ycfw);
            drillModel.setDrill(listYcData);
            drillModel.setGridAccuracy(vo.getPrecision());
            drillModel.setCoordinateType("jingweidu");
            drillModel.setIsLimited("N");
            drillModel.setRequestGuid(vo.getUuid());
            drillModel.setAverageCoordinateX(x);
            drillModel.setAverageCoordinateY(y);
            //设置文件路径
            String userDir = System.getProperty("user.dir");
            String fileWallUrl = userDir+File.separator +"wall"+File.separator+vo.getUuid()+".json";
            String filePlanUrl = userDir+File.separator +"plane"+File.separator+vo.getUuid()+".json";

            drillModel.setPlanePath(filePlanUrl);
            drillModel.setWallPath(fileWallUrl);
            //调用接口
            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.APPLICATION_JSON_UTF8);
            HttpEntity<String> request = new HttpEntity<>(mapper.writeValueAsString(drillModel), headers);

            restTemplate.postForEntity(ycUrl, request, String.class);
            System.out.println("岩层生成路径:"+ycUrl+"\n 传递的其余参数:"+drillModel.toString()+"\n");


//            ResponseEntity<String> responseEntity = restTemplate.postForEntity(ycUrl, request, String.class);
//            String body = responseEntity.getBody();
//
//            Map<String, Object> bodyMap =  mapper.readValue(body, new TypeReference<Map<String, Object>>() {});
//
//            if(("N").equals(bodyMap.get("Status"))){
//                System.out.println("生成岩层失败="+bodyMap.get("Content"));
//                TabYc tabYc = tabYcMapper.selectYcByUuid(vo.getUuid());
//                tabYc.setState(-1);
//                tabYcMapper.upTabYc(tabYc);
//
//
//                tabTask.setTaskState(2);
//                tabTask.setRemark("生成岩层失败:"+bodyMap.get("Content").toString());
//                tabTask.setUpTime(new Date());
//                tabTask.setProgress(0d);
//                tabTaskMapper.upTabTask(tabTask);
//                return null;
//            }
//            System.out.println("生成岩层="+vo.getYcmc()+";="+new Date());
//
//            String content = bodyMap.get("Content").toString();
//
//            CollectionType listType = mapper.getTypeFactory().constructCollectionType(ArrayList.class, PlaneWall.class);
//            List<PlaneWall> datas = mapper.readValue(content, listType);
//            List<PlaneWall> walls = new ArrayList<>();
//            List<PlaneWall> planes = new ArrayList<>();
//            for (PlaneWall wall:datas) {
//                if(wall.getLevel()<=0){
//                    walls.add(wall);
//                }else{
//                    planes.add(wall);
//                }
//            }
//            //写入文件
//            String wallStr = mapper.writeValueAsString(walls);
//            String planeStr = mapper.writeValueAsString(planes);
//
//            String userDir = System.getProperty("user.dir");
//            String fileWallUrl = userDir+File.separator +"wall"+File.separator+vo.getUuid()+".txt";
//            File fileWall = new File(fileWallUrl);
//            writeTxt(wallStr,fileWall);
//
//            String filePlaneUrl = userDir+File.separator +"plane"+File.separator+vo.getUuid()+".txt";
//            File filePlane = new File(filePlaneUrl);
//            writeTxt(planeStr,filePlane);
//
//            TabYc tabYc = tabYcMapper.selectYcByUuid(vo.getUuid());
//            tabYc.setWall(fileWallUrl);
//            tabYc.setPlane(filePlaneUrl);
//            tabYc.setState(1);
//            tabYc.setSettingId(buffer.toString());
//            tabYcMapper.upTabYc(tabYc);
//
//            tabTask.setProgress(100d);
//            tabTask.setTaskState(1);
//            tabTask.setUpTime(new Date());
//            tabTaskMapper.upTabTask(tabTask);
        } catch (Exception e) {
            e.printStackTrace();
         //   TabYc tabYc = tabYcMapper.selectYcByUuid(vo.getUuid());
            tabYc.setState(-1);
            tabYcMapper.upTabYc(tabYc);

           // TabTask tabTask = tabTaskMapper.getByUuid(vo.getUuid());
            tabTask.setTaskState(2);
            tabTask.setRemark("生成岩层失败:系统异常");
            tabTask.setUpTime(new Date());
            tabTask.setProgress(0d);
            tabTaskMapper.upTabTask(tabTask);
            return r.failure(-1,"系统异常,请联系管理员");
        }
        tabYcMapper.upTabYc(tabYc);
        return r;
    }


    @Override
    public Result checkYcName(String ycName) {
        Result r = new Result();
        Integer num = tabYcMapper.checkYcName(ycName);
        r.setData(num);
        return r;
    }

    @Override
    public Result getYcByUuid(String uuid) {
        Result r = new Result();
        TabYc yc = tabYcMapper.selectYcByUuid(uuid);
        if(null == yc){
            throw new GlobalExceptionHandler(404,"岩层不存在");
        }
        Map<String,Object> m = new HashMap<>();
        m.put("ycName",yc.getYcName());
        m.put("plane",FileUtil.getContent(yc.getPlane()));
        m.put("wall",FileUtil.getContent(yc.getWall()));
        m.put("uuid",yc.getUuid());
        m.put("ycTime",yc.getYcTime());
        r.setData(m);
        return r;
    }

    @Override
    public Result setYcMarkerColor(YcConditionVo vo) {
        Result r = new Result();
        List<String> zkData = vo.getZkData();
        //过滤点范围
        SpatialRelationship spatialRelationship = new SpatialRelationship();

        List<GeoPoint> pointList = new ArrayList<>();
        Map<String,Object> map = new HashMap<>();
        for (String str : zkData){
            String[] data = str.split(",");
            GeoPoint point = new GeoPoint(Double.valueOf(data[2]),Double.valueOf(data[3]));
            map.put("settingId",data[0]);
            map.put("ZKBH",data[1]);
            point.setProperties(map);
            pointList.add(point);
        }
        //根据经纬去重
        List<GeoPoint> pointListNew = pointList.stream().collect(Collectors.collectingAndThen(Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(o -> o.getX() + ";" + o.getY()))), ArrayList::new));
        List<double[]> zkfw = vo.getZkfw();
        double[][] doubles = zkfw.toArray(new double[zkfw.size()][2]);
        GeoPolygon geoPolygon = new GeoPolygon(doubles);
        List<GeoPoint> intersects = spatialRelationship.intersects(pointListNew, geoPolygon);

//        if(intersects.isEmpty()){
//            return r.failure(-1,"钻孔不在模型范围内，请重新绘制");
//        }

        List<TabMarkerColor> colorList = new ArrayList<>();
        //组装数据
        for (GeoPoint point:intersects) {
            String ZKBH = point.getProperties().getProperty("ZKBH");
            String settingId = point.getProperties().getProperty("settingId");
            //钻孔对应的岩层
            List<TabMarkerColor> colors = settingMapper.setYcMarker(ZKBH,settingId);
            colorList.addAll(colors);
        }
        colorList = colorList.stream().collect(Collectors.collectingAndThen(Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(o -> o.getDrillMarker()))), ArrayList::new));
        Collections.sort(colorList, Comparator.comparing(TabMarkerColor::getTCCDSD));
        if(colorList.isEmpty()){
            return r.failure(-1,"生成模型基础数据已不存在，请刷新后重试");
        }
        r.setData(colorList);
        return r;
    }

    private void writeTxt(String content,File file){
        try {
            if(!file.getParentFile().exists()){
                file.getParentFile().mkdirs();
            }
            FileWriter writer = new FileWriter(file , true);
            BufferedWriter out = new BufferedWriter(writer);
            out.write(content);
            out.flush(); // 把缓存区内容压入文件
            out.close(); // 关闭文件
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}
